#include "LecteurPhraseAvecArbre.h"

#include <stdlib.h>
#include <iostream>
using namespace std;

////////////////////////////////////////////////////////////////////////////////
LecteurPhraseAvecArbre::LecteurPhraseAvecArbre(string nomFich) :
	ls(nomFich), ts() {
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecArbre::analyse() {
	arbre=programme();
	cout << "Syntaxe correcte." << endl;
}


////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::programme() {
// <programme> ::= debut <seqInst> fin FIN_FICHIER

	sauterSymCour(DEBUT);
	Noeud* si = seqInst();
	sauterSymCour(FIN);
	testerSymCour("<FINDEFICHIER>");
	return si;
}


////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::seqInst() {
// <seqInst> ::= <inst> ; { <inst> ; }

	NoeudSeqInst* si = new NoeudSeqInst();
	do {
		si->ajouteInstruction(inst());
		sauterSymCour(";");
	} while ((ls.getSymCour()=="<VARIABLE>") || (ls.getSymCour()==TANTQUE) ||
			(ls.getSymCour()==REPETER) || (ls.getSymCour()==SI) ||
			(ls.getSymCour()==POUR) || (ls.getSymCour()==LIRE) ||
			(ls.getSymCour()==ENTIER) || (ls.getSymCour()==FLOAT) ||
			(ls.getSymCour()==CARACT) || (ls.getSymCour()==CHAINE) ||
			(ls.getSymCour()==ECRIRE));
	/*} while  (ls.getSymCour()!=FIN && ls.getSymCour()!=FINTANTQUE &&
	ls.getSymCour()!=JUSQUA && ls.getSymCour()!=FINSI &&
	ls.getSymCour()!=SINON && ls.getSymCour()!=SINONSI &&
	ls.getSymCour()!=FINPOUR);*/
	// (ls.getSymCour()!="fin" || ls.getSymCour()!="fintantque" || ls.getSymCour()!="finsi" || ls.getSymCour()!="sinon" || ls.getSymCour()!="sinonsi");
	// tant que le symbole courant est un debut possible d'instruction...
	//while (ls.getSymCour()=="<VARIABLE>");

	return si;
}

////////////////////////////////////////////////////////////////////////////////
/*void LecteurPhraseSimple::inst() {
// <inst> ::= <affectation>

	affectation();
}*/


////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::inst()
//    <inst> ::= <affectation> | <instSi> | <instTq> | <instRepeter> | <instLire> | <instEcrire>
{
	if (ls.getSymCour()=="<VARIABLE>")
		return affectation();
	else if (ls.getSymCour()==ENTIER || ls.getSymCour()==FLOAT || ls.getSymCour()==CHAINE || ls.getSymCour()==CARACT) // on lance la "conditionr qui contiendra elle-meme des instructions. (condition = ExpBool)
		return declaration();
	else if (ls.getSymCour()==SI) // on lance la "conditionr qui contiendra elle-meme des instructions. (condition = ExpBool)
		return instSi();
	else if (ls.getSymCour()==TANTQUE) // idem que if
		return instTq();
	else if (ls.getSymCour()==REPETER) // idem que if
		return instRepeter();
	else if (ls.getSymCour()==POUR) // idem que if
		return instPour();
	else if (ls.getSymCour()==LIRE) // instruction pour lire une variable au clavier. (accepte que des <VARIABLE>
		return instLire();
	else if (ls.getSymCour()==ECRIRE) // instruction pour ecrire a l'ecran des variable, entier, chaine.
		return instEcrire();
    else
	erreur("<inst>");
		return NULL;
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::instSi()
//  <instSi> ::= si ( <expBoolOu> ) <seqInst> { sinonsi ( <expBoolOu> ) <seqInst> }
//  [ sinon <seqInst> ] finsi
{
	   Noeud* suivant = NULL;
	   Noeud* exp = NULL;
	   Noeud* seqinst = NULL;
	   Noeud* si = NULL;
	if (ls.getSymCour()==SI) {

		sauterSymCour(SI);
		sauterSymCour("(");
		exp = expBoolOu();
		sauterSymCour(")");
		seqinst = seqInst();
		suivant = instSi();
		//NoeudSi* si = new NoeudSi(exp,seqinst, fact);
		//NoeudSi* pres =si;
	//	if (suivant == NULL)
			sauterSymCour(FINSI);
			si = new NoeudSi(exp,seqinst,suivant);
	}
	else if (ls.getSymCour()==SINONSI) {

		sauterSymCour(SINONSI);
		sauterSymCour("(");
		exp = expBoolOu();
		sauterSymCour(")");
		seqinst = seqInst();
		suivant = instSi();
		//NoeudSi* sinonsi = new NoeudSi(exp,seqinst,fact);
	//	pres->setSuivant(sinonsi);
	//	pres = sinonsi;
		si = new NoeudSi(exp,seqinst,suivant);
	}
	else if (ls.getSymCour()==SINON) {

		ls.suivant();
		seqinst = seqInst();
		exp = ts.chercheAjoute(Symbole("1"));
		//fact=ts.chercheAjoute(Symbole("1"));
	//	NoeudSi* sinon = new NoeudSi(ts.chercheAjoute(Symbole("1")),seqinst,fact);
	//	pres->setSuivant(sinon);
		si = new NoeudSi(exp,seqinst,suivant);
	}
	//else {
	//	sauterSymCour(FINSI);
	//	cout << "erreur" << endl;
	//	si = NULL;
		//exit(0);
	//}

	return si;
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::instTq()
// <instTq> ::= tantque ( <expBool> ) <seqInst> fintantque
{
	sauterSymCour(TANTQUE);
	sauterSymCour("(");
	Noeud* exp = expBoolOu();
	sauterSymCour(")");
	Noeud* seqinst = seqInst();
	sauterSymCour(FINTANTQUE);
	return new NoeudTantQue(exp,seqinst);
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::instPour()
// <instPour> ::= pour ( affectation ; <expBool>; affectation ) <seqInst> finpour
{
	sauterSymCour(POUR);
	sauterSymCour("(");
	Noeud* aff = affectation();
	sauterSymCour(";");
	Noeud* exp = expBoolOu();
	sauterSymCour(";");
	Noeud* aff2 = affectation();
	sauterSymCour(")");
	Noeud* seqinst = seqInst();
	sauterSymCour(FINPOUR);
	return new NoeudPour(aff,aff2,exp,seqinst);
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::instRepeter()
// <instRepeter> ::= repeter <seqInst> jusqua ( <expBool> )
{
	sauterSymCour(REPETER);
	Noeud* seqinst = seqInst();
	sauterSymCour(JUSQUA);
	sauterSymCour("(");
	Noeud* exp = expBoolOu();
	sauterSymCour(")");
	return new NoeudRepeter(exp,seqinst);
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::instLire() //<instLire> ::= lire ( <variable> )
{
	Noeud* fact = NULL;
	sauterSymCour(LIRE);
	sauterSymCour("(");
	if (ls.getSymCour()=="<VARIABLE>" && ts.varaibleExiste(ls.getSymCour())) {
		fact = facteur();
		sauterSymCour(")");
	}
	else
		erreur("<variable>");
	return new NoeudLire(fact);
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::instEcrire() //   <instEcrire> ::= ecrire ( <expression> | <chaine> )
{
	sauterSymCour(ECRIRE);
	sauterSymCour("(");
	//if (ls.getSymCour()=="<STRING>") {
	//	Noeud* fact= facteur();
	//}
	//else
		Noeud* exp = expression();
	sauterSymCour(")");
	return new NoeudEcrire(exp);
}


////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::affectation() {
// <affectation> ::= <variable> = <expression>
	testerSymCour("<VARIABLE>");
	if (ts.varaibleExiste(ls.getSymCour()))
	  {
	Noeud* var = ts.chercheAjoute(ls.getSymCour());
	ls.suivant();
	sauterSymCour("=");
	Noeud* exp = expBoolOu();
	  }
	else
	  exit(-1);
	return new NoeudAffectation(var,exp);
}


////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::declaration() {
// <declaration> ::= <type> <variable>
        Noeud* type = type();
	if (!(ts.varaibleExiste(ls.getSymCour())))
	  {
	Noeud* var = ts.chercheAjoute(ls.getSymCour());
	ls.suivant();
	//	sauterSymCour("=");
	//	Noeud* exp = expBoolOu();
	  }
	else
	  exit(-1);
	return new NoeudDeclaration(var,type);
}


////////////////////////////////////////////////////////////////////////////////
/*void LecteurPhraseSimple::expBool()
// <expBool> ::= <relation> { <opBool> <relation> }
{n
	if (ls.getSymCour()==NON) {
			sauterSymCour(NON);
	}
	relation();
	while (ls.getSymCour()==ET || ls.getSymCour()==OU) {
		opBool();
		ls.suivant();
		relation();
	}
}*/

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::expBoolOu()
// <expBool> ::= <expBoolEt> { <opOu> <expBoolOu> }
{
	Noeud* rel = expBoolEt();
	while (ls.getSymCour()==OU) {
		Symbole operateur = opOu();
		Noeud* relDroit = expBoolEt();
		rel = new NoeudOperateurBinaire(operateur,rel,relDroit); // const. du noeud
	}
	return rel;
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::expBoolEt()
// <expBoolEt> ::= <relation> { <opEt> <expBoolOu> }
{
	Noeud* rel = relation();
	while (ls.getSymCour()==ET) {
		Symbole operateur = opEt();
		Noeud* relDroit = relation();
		rel = new NoeudOperateurBinaire(operateur,rel,relDroit); // const. du noeud
	}
	return rel;
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::relation()
// <relation> ::= <expBool> { <opRel> <expBool> }
// <expression> { <opRel> <expression> }
{
	Noeud* exp = expression();

	while (ls.getSymCour()=="==" || ls.getSymCour()=="!=" ||
			ls.getSymCour()=="<" || ls.getSymCour()=="<=" ||
			ls.getSymCour()==">" || ls.getSymCour()==">=") {
	//	opRel();
	//	expression();
		Symbole operateur = opRel();
		Noeud* expDroit = expression();
		exp = new NoeudOperateurBinaire(operateur,exp,expDroit); // const. du noeud
	}
	return exp;
}


////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::expression() {
// <expression> ::= <terme> { <opAdd> <terme> }
	Noeud* term = terme();
	while (ls.getSymCour()=="+" || ls.getSymCour()=="-") {
		Symbole operateur =opAdd();
		Noeud* termDroit = terme();
		term = new NoeudOperateurBinaire(operateur,term,termDroit); // const. du noeud
	}
	return term;
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::terme() {
// <terme> ::= <facteur> { <opBinaire> <facteur> }
	//cout << "trace 2" << endl;
	//facteur();
	Noeud* fact = facteur();
	while (ls.getSymCour()=="*" || ls.getSymCour()=="/") {
		//opMult();
		//facteur();
		Symbole operateur =opMult(); // on stocke le symbole de l'opérateur
		Noeud* factDroit=facteur(); // lecture de l'operande droit
		fact = new NoeudOperateurBinaire(operateur,fact,factDroit); // const. du noeud
	}
	return fact;
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::facteur() {
// <facteur> ::= <entier>  |  <variable>  |  - <facteur>  |  ( <expression> )
// <facteur> ::= <entier> | <variable> | <opUnaire> <expBool> | ( <expBool> )

	Noeud* fact=NULL;
	if (ls.getSymCour()=="<VARIABLE>" || ts.varaibleExiste(ls.getSymCour())) {
		fact=ts.chercheAjoute(ls.getSymCour());
		ls.suivant();
	}
	if (ls.getSymCour()=="<ENTIER>" || ls.getSymCour()=="<CHAINE>" || ls.getSymCour()=="<FLOAT>" || ls.getSymCour()=="<CARACT>") {
		fact=ts.chercheAjoute(ls.getSymCour());
		ls.suivant();
	}

	else if (ls.getSymCour()=="-")  {
		ls.suivant();
		//opUnaire();
	//	facteur();
		// on représente le moins unaire (- facteur) par une soustractin binaire (0 - facteur)
		fact = new NoeudOperateurBinaire(Symbole("-"), ts.chercheAjoute(Symbole("0")), facteur());
	}
	else if (ls.getSymCour()==NON)  {
		ls.suivant();
	//	opUnaire();
	//	facteur();
		 // cout << "nonononono" << endl;
			fact= ts.chercheAjoute(Symbole("1"));
	//		  cout << "nonononono" << endl;
		// on représente le nom par une valeur NULL a droite.
	//	fact = new NoeudOperateurBinaire(Symbole(NON), facteur(), fact);
		  fact = new NoeudOperateurBinaire(Symbole("!"), fact, facteur());
		//  cout << "nonononono" << endl;
	}
	else if (ls.getSymCour()=="(") {
		ls.suivant();
	  	fact=expBoolOu();
		sauterSymCour(")");
	}
	else
	erreur("<facteur>");
	return fact;
}


////////////////////////////////////////////////////////////////////////////////
/*void LecteurPhraseSimple::opBinaire()
// <opBinaire> ::= + | - | *  | /
{
	if (ls.getSymCour()=="+" || ls.getSymCour()=="-" ||
		ls.getSymCour()=="*" || ls.getSymCour()=="/")
		ls.suivant();
	else
		erreur("<opBinaire>");
}*/

/*////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseSimple::opBool()
// <opBool> ::= et | ou
{
	if (ls.getSymCour()==ET || ls.getSymCour()==OU)
		ls.suivant();
	else
		erreur("<opBool>");

}*/

////////////////////////////////////////////////////////	return operateur;////////////////////////
Symbole LecteurPhraseAvecArbre::opEt()
// <opBool> ::= et
{
	Symbole operateur;
	if (ls.getSymCour()==ET) {
		operateur=ls.getSymCour();
		ls.suivant();
	}
	else
		erreur("<opBoolEt");
	return operateur;
}

////////////////////////////////////////////////////////////////////////////////
Symbole LecteurPhraseAvecArbre::opOu()
// <opBool> ::= ou
{
	Symbole operateur;
	if (ls.getSymCour()==OU) {
		operateur=ls.getSymCour();
		ls.suivant();
	}
	else
		erreur("<opBoolOu>");
	return operateur;
}

////////////////////////////////////////////////////////////////////////////////
Symbole LecteurPhraseAvecArbre::opRel()
// <opRel> ::= == | != | < | <= | > | >=
{
	Symbole operateur;
	if (ls.getSymCour()=="==" || ls.getSymCour()=="!=" ||
		ls.getSymCour()=="<" || ls.getSymCour()=="<=" ||
		ls.getSymCour()==">" || ls.getSymCour()==">=") {
		operateur=ls.getSymCour();
		ls.suivant();
	}
	else
		erreur("<opRel>");
	return operateur;
}

////////////////////////////////////////////////////////////////////////////////
Symbole LecteurPhraseAvecArbre::opUnaire()
// <opUnaire> ::= - | non
{
	Symbole operateur;
	if (ls.getSymCour()=="-" || ls.getSymCour()==NON) {
		operateur=ls.getSymCour();
		ls.suivant();
	}
	else
		erreur("<opUnaire>");
	return operateur;

}


////////////////////////////////////////////////////////////////////////////////
Symbole LecteurPhraseAvecArbre::opAdd()
// <opAdd> ::= + | -
{
	Symbole operateur;
	if (ls.getSymCour()=="+" || ls.getSymCour()=="-") {
		operateur=ls.getSymCour();
		ls.suivant();
	}
	else
		erreur("<opAdd>");
	return operateur;
}

////////////////////////////////////////////////////////////////////////////////
Symbole LecteurPhraseAvecArbre::opMult()
// <opMult> ::= *  | /
{
	Symbole operateur;
	if (ls.getSymCour()=="*" || ls.getSymCour()=="/") {
		operateur=ls.getSymCour();
		ls.suivant();
	}
	else
		erreur("<opMult>");
	return operateur;
}



////////////////////////////////////////////////////////////////////////////////
Symbole LecteurPhraseAvecArbre::type()
// <type> ::= entier | reel | chaine | caract
{
	Symbole operateur;
	if (ls.getSymCour()==ENTIER || ls.getSymCour()==FLOAT || ls.getSymCour()==CHAINE || ls.getSymCour()==CARACT) {
		operateur=ls.getSymCour();
		ls.suivant();
	}
	else
		erreur("<type>");
	return operateur;
}


////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecArbre::testerSymCour(string ch) {
	if (ls.getSymCour() != ch) {
		cout << endl << "-------- Erreur ligne " << ls.getLigne()
				<< " - Colonne " << ls.getColonne() << endl << "   Attendu : "
				<< ch << endl << "   Trouve  : " << ls.getSymCour() << endl
				<< endl;
		exit(0); // plus tard, on levera une exception
	}
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecArbre::sauterSymCour(string ch) {
	testerSymCour(ch);
	ls.suivant();
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecArbre::erreur(string mess) {
	cout << endl << "-------- Erreur ligne " << ls.getLigne() << " - Colonne "
			<< ls.getColonne() << endl << "   Attendu : " << mess << endl
			<< "   Trouve  : " << ls.getSymCour() << endl << endl;
	exit(0); // plus tard, on levera une exception
}


